const os = require('os');
const {fork} = require("child_process");
const path = require("path");
const logger = require("../logger");
const {progressLogger} = require("../utils/util");

let workFn;

function singleProcess(files, options) {
  let workFileIndex = 0;

  const callback = (log) => {
    options.logger && log && logger.addTask(log);

    if (workFileIndex++ < files.length) {
      workFn(files[workFileIndex], options, callback)
    } else if (workFileIndex === files.length) {
      options?.after?.()
    }
    progressLogger();
  }
  workFn(files[workFileIndex], options, callback);
}


function dispatcher(options, files) {
  if (options.multiProcess) {
    let MAX_PROCESS = typeof options.multiProcess === 'number' ? options.multiProcess : (os.cpus().length - 1);
    if (MAX_PROCESS > os.cpus().length - 1 || MAX_PROCESS < 1) {
      MAX_PROCESS = os.cpus().length - 1;
    }

    const processList = [];
    let waitWorkFileIdx = 0;
    let completeFiles = 0;

    const sendTask = (childProcess) => {
      if (waitWorkFileIdx >= global.__shouldCheckFileCount) {
        childProcess.kill();
        return
      }
      childProcess.send(files[waitWorkFileIdx++]);
    };

    while (processList.length < MAX_PROCESS) {
      const child = fork(path.join(__dirname, './child_worker.js'), {
        serialization: "advanced",
      });

      child.on('message', (log) => {
        completeFiles++;
        progressLogger();

        if (completeFiles >= global.__shouldCheckFileCount) {
          if (completeFiles === global.__shouldCheckFileCount) {
            options?.after?.();
          }
          child.kill();
          return;
        }

        options.logger && log && logger.addTask(log);
        sendTask(child);
      })
      processList.push(child);
    }
    processList.forEach(sendTask)
  } else {
    workFn = options.dealFn;
    singleProcess(files, options);
  }
}

module.exports = dispatcher
